#pragma once

#include <GdiPlus.h>

namespace Gdiplus {
    class Effect {
        friend class Bitmap;
        friend class Graphics;
    public:
        Effect() {
            auxDataSize = 0;
            auxData = NULL;
            nativeEffect = NULL;
            useAuxData = FALSE;
        }

        virtual ~Effect() {
            // pvData is allocated by ApplyEffect. Return the pointer so that
            // it can be freed by the appropriate memory manager.

            DllExports::GdipFree(auxData);

            // Release the native Effect.

            DllExports::GdipDeleteEffect(nativeEffect);
        }

        INT GetAuxDataSize() const {
            return auxDataSize;
        }

        VOID *GetAuxData() const {
            return auxData;
        }

        VOID UseAuxData(const BOOL useAuxDataFlag) {
            useAuxData = useAuxDataFlag;
        }

        Status GetParameterSize(UINT *size) {
            return DllExports::GdipGetEffectParameterSize(nativeEffect, size);
        }

    protected:

        Status SetParameters(const void *params, const UINT size) {
            return DllExports::GdipSetEffectParameters(nativeEffect, params, size);
        }

        Status GetParameters(UINT *size, void *params) {
            return DllExports::GdipGetEffectParameters(nativeEffect, size, params);
        }

        // protected data members.

        CGpEffect *nativeEffect;
        INT auxDataSize;
        VOID *auxData;
        BOOL useAuxData;
    };

    // Blur
    class Blur : public Effect {
    public:

        // constructors cannot return an error code.

        Blur() {
            DllExports::GdipCreateEffect(BlurEffectGuid, &nativeEffect);
        }

        Status SetParameters(const BlurParams *parameters) {
            UINT size = sizeof(BlurParams);
            return Effect::SetParameters(parameters, size);
        }

        Status GetParameters(UINT *size, BlurParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // Sharpen
    class Sharpen : public Effect {
    public:

        Sharpen() {
            DllExports::GdipCreateEffect(SharpenEffectGuid, &nativeEffect);
        }

        Status SetParameters(const SharpenParams *parameters) {
            UINT size = sizeof(SharpenParams);
            return Effect::SetParameters(parameters, size);
        }

        Status GetParameters(UINT *size, SharpenParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // RedEye Correction
    class RedEyeCorrection : public Effect {
    public:

        // constructors cannot return an error code.

        RedEyeCorrection() {
            DllExports::GdipCreateEffect(RedEyeCorrectionEffectGuid, &nativeEffect);
        }

        Status SetParameters(const RedEyeCorrectionParams *parameters) {
            Status status = InvalidParameter;

            if (parameters) {
                RedEyeCorrectionParams *inputParam =
                        (RedEyeCorrectionParams *) parameters;

                UINT size = sizeof(RedEyeCorrectionParams) +
                            inputParam->numberOfAreas * sizeof(RECT);

                status = Effect::SetParameters(parameters, size);
            }

            return status;
        }

        Status GetParameters(UINT *size, RedEyeCorrectionParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // Brightness/Contrast
    class BrightnessContrast : public Effect {
    public:
        BrightnessContrast() {
            DllExports::GdipCreateEffect(BrightnessContrastEffectGuid, &nativeEffect);
        }

        Status SetParameters(const BrightnessContrastParams *parameters) {
            UINT size = sizeof(BrightnessContrastParams);
            return Effect::SetParameters((VOID *) parameters, size);
        }

        Status GetParameters(UINT *size, BrightnessContrastParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // Hue/Saturation/Lightness
    class HueSaturationLightness : public Effect {
    public:
        HueSaturationLightness() {
            DllExports::GdipCreateEffect(HueSaturationLightnessEffectGuid, &nativeEffect);
        }

        Status SetParameters(const HueSaturationLightnessParams *parameters) {
            UINT size = sizeof(HueSaturationLightnessParams);
            return Effect::SetParameters((VOID *) parameters, size);
        }

        Status GetParameters(UINT *size, HueSaturationLightnessParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // Highlight/Midtone/Shadow curves
    class Levels : public Effect {
    public:
        Levels() {
            DllExports::GdipCreateEffect(LevelsEffectGuid, &nativeEffect);
        }

        Status SetParameters(const LevelsParams *parameters) {
            UINT size = sizeof(LevelsParams);
            return Effect::SetParameters((VOID *) parameters, size);
        }

        Status GetParameters(UINT *size, LevelsParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // Tint
    class Tint : public Effect {
    public:
        Tint() {
            DllExports::GdipCreateEffect(TintEffectGuid, &nativeEffect);
        }

        Status SetParameters(const TintParams *parameters) {
            UINT size = sizeof(TintParams);
            return Effect::SetParameters((VOID *) parameters, size);
        }

        Status GetParameters(UINT *size, TintParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // ColorBalance
    class ColorBalance : public Effect {
    public:
        ColorBalance() {
            DllExports::GdipCreateEffect(ColorBalanceEffectGuid, &nativeEffect);
        }

        Status SetParameters(const ColorBalanceParams *parameters) {
            UINT size = sizeof(ColorBalanceParams);
            return Effect::SetParameters((VOID *) parameters, size);
        }

        Status GetParameters(UINT *size, ColorBalanceParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

    // ColorMatrix
    class ColorMatrixEffect : public Effect {
    public:
        // constructors cannot return an error code.
        ColorMatrixEffect() {
            DllExports::GdipCreateEffect(ColorMatrixEffectGuid, &nativeEffect);
        }

        Status SetParameters(const ColorMatrix *matrix) {
            UINT size = sizeof(ColorMatrix);
            return Effect::SetParameters(matrix, size);
        }

        Status GetParameters(UINT *size, ColorMatrix *matrix) {
            return Effect::GetParameters(size, (VOID *) matrix);
        }
    };

    // ColorLUT
    class ColorLUT : public Effect {
    public:

        // constructors cannot return an error code.

        ColorLUT() {
            DllExports::GdipCreateEffect(ColorLUTEffectGuid, &nativeEffect);
        }

        Status SetParameters(const ColorLUTParams *lut) {
            UINT size = sizeof(ColorLUTParams);
            return Effect::SetParameters(lut, size);
        }

        Status GetParameters(UINT *size, ColorLUTParams *lut) {
            return Effect::GetParameters(size, (VOID *) lut);
        }
    };

    // Color Curve
    class ColorCurve : public Effect {
    public:
        ColorCurve() {
            DllExports::GdipCreateEffect(ColorCurveEffectGuid, &nativeEffect);
        }

        Status SetParameters(const ColorCurveParams *parameters) {
            UINT size = sizeof(ColorCurveParams);
            return Effect::SetParameters((VOID *) parameters, size);
        }

        Status GetParameters(UINT *size, ColorCurveParams *parameters) {
            return Effect::GetParameters(size, (VOID *) parameters);
        }
    };

}
namespace ui {
    namespace GdiHelper {
        Gdiplus::Bitmap *CreateBitmapFromHBITMAP(HBITMAP hBitmap);
    }
}
